package com.xiyuan.smartutils.control;

import com.xiyuan.smartutils.Asserts;
import com.xiyuan.smartutils.Randoms;
import com.xiyuan.smartutils.StrUtils;
import com.xiyuan.smartutils.Threads;
import com.xiyuan.smartutils.logging.LogFactory;
import com.xiyuan.smartutils.logging.Logger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池控制器，指定池最小值、最大值、初始值，允许线程空闲时长和允许缓存事件大小<br>
 * <br>
 * 1.创建时创建初始值大小的线程池，创建事件队列，和主线程<br>
 * 2.其他线程通过post传递事件可执行事件<br>
 * 3.主线程调度线程池处理事件，并检查线程池空闲线程
 *
 * @version v1.0.0 @author lgz 2017-8-27 新建与整理
 */
public class ThreaderController extends Threadx {
    private static final Logger log = LogFactory.getLogger(ThreaderController.class);
    
    // 线程池最小数目
    private volatile int poMinSize;
    // 线程池最大数目
    private volatile int poMaxSize;
    // 线程池线程空闲时长(毫秒)
    private volatile int poIdleTimeMs;
    // 线程池队列大小
    private volatile int poQueueSize;
    // 线程池线程等待超时时长(毫秒)，默认5*1000
    private volatile int threadTimeoutMs;
    
    // 指定线程组
    private ThreadGroup threadGroup;
    // 指定线程名
    private String threadName;
    // 是否打印繁忙日志
    private boolean isLogger;
    
    // 所有线程列表
    private final LinkedList<Threader> theaderList;
    // 等待处理的可执行事件
    private final Queue<Runnable> queue;
    
    // 活跃线程数
    private final AtomicInteger activeSize;
    
    // 是否初始化
    private boolean isInited = false;
    
    //  // 控制器ID
    private String id;
    
    public ThreaderController() {
        this(null);
    }
    
    public ThreaderController(String id) {
        
        this.id = id;
        this.threadName = newName("Controller-");
        this.threadTimeoutMs = 5 * 1000;
        this.theaderList = new LinkedList<>();
        this.queue = new Queue<Runnable>();
        this.activeSize = new AtomicInteger();
        this.threadGroup = new ThreadGroup(threadName);
    }
    
    protected final String newName(String prefix) {
        return prefix + Randoms.random(1, Randoms.ResultType.LETTERS_LOWER_CASE) + Randoms.random(4);
    }
    
    
    @Override
    /** 不再支持子类重写，创建后不能修改 */ protected final ThreadGroup getThreadGroup() {
        return threadGroup;
    }
    
    public String getId() {
        return this.id;
    }
    
    
    @Override
    /** 不再支持子类重写，修改请通过setThreadName设置 */ protected final String getThreadName() {
        return threadName;
    }
    
    /**
     * 设置线程池必须的四个参数，支持创建后重新设置
     *
     * @param minPoSize   线程池最小值
     * @param maxPoSize   线程池最大值
     * @param poIdleTime  线程池线程空闲检查时长，单位秒
     * @param poQueueSize 线程池允许缓存事件大小
     * @return this instance
     */
    @SuppressWarnings("unchecked")
    public <T extends ThreaderController> T init(int minPoSize, int maxPoSize, int poIdleTime, int poQueueSize) {
        set(minPoSize, maxPoSize, poIdleTime, poQueueSize);
        this.isInited = true;
        return (T) this;
    }
    
    /*********************************************************************************************/
    // 参数设置
    /*********************************************************************************************/
    
    /**
     * 设置线程池中线程等待超时时长
     *
     * @param threadTimeoutMs 超时时长，单位毫秒
     */
    public void setThreadTimeoutMs(int threadTimeoutMs) {
        this.threadTimeoutMs = threadTimeoutMs;
    }
    
    /**
     * 设置线程池中线程名，创建前设置，创建后修改无效，控制线程名为Controller-${threadName}
     *
     * @param threadName 线程名
     */
    public void setThreadName(String threadName) {
        Asserts.as(!isRunning() ? null : "线程池创建后不支持修改");
        this.threadName = threadName;
    }
    
    @Override
    public final void setDaemon(boolean isDaemon) {
        super.setDaemon(isDaemon);
        synchronized (theaderList) {
            for (int i = 0; i < theaderList.size(); i++) {
                theaderList.get(i).setDaemon(isDaemon);
            }
        }
    }
    
    /**
     * 设置线程池在繁忙时是否打印日志，未设置默认是打印
     *
     * @param isLogger 是否打印日志
     */
    public void setLogger(boolean isLogger) {
        this.isLogger = isLogger;
    }
    
    /**
     * 设置线程池必须的四个参数，支持创建后重新设置
     *
     * @param minPoSize   线程池最小值
     * @param maxPoSize   线程池最大值
     * @param poIdleTime  线程池线程空闲时长，单位秒
     * @param poQueueSize 线程池允许缓存事件大小
     */
    public ThreaderController set(int minPoSize, int maxPoSize, int poIdleTime, int poQueueSize) {
        this.poMinSize = Math.max(minPoSize, 1);
        this.poMaxSize = Math.max(maxPoSize, minPoSize);
        this.poIdleTimeMs = Math.max(poIdleTime, 1) * 1000;
        this.poQueueSize = Math.max(poQueueSize, (this.poMaxSize * 3));
        
        return this;
    }
    
    /*********************************************************************************************/
    // 创建&销毁
    
    /*********************************************************************************************/
    
    @Override
    public boolean openBefore() {
        // 0 检查初始化
        Asserts.as(isInited ? null : "线程池尚未初始化,请调用init方法完成初始化操作");
        
        // 1.检查是否有设置
        // 1.1有设置ID的，线程名为ID首字母大写
        if (id != null) {threadName = StrUtils.toUpperFirstChar(id);}
        
        // 2.判断线程池参数是否正确
        Asserts.as((poMaxSize >= poMinSize && poMinSize > 0 && poIdleTimeMs > 0 && poQueueSize > 0)
                   ? null
                   : "线程池服务配置参数不正确");
        
        // 3.初始化创建线程操作者
        for (int i = 0; i < poMinSize; i++) {openThreader();}
        
        return true;
    }
    
    @Override
    public void closeAfter() {
        closeThreaders();
        log.info(String.format("线程池[%s]监视线程退出", threadName));
    }
    
    @Override
    public void loop() {
        // 如果线程池中线程比最小值大，则检查线程池是否有空闲线程，有则关闭
        if (theaderList.size() > poMinSize) {chkThreaders();}
        
        if (isLogger) {
            // 当前线程池数据
            log.info(String.format("线程池[name:%s,min:%d,max:%d,cur:%d,active:%d,queue:%d,idleTime:%d]",
                                   threadName,
                                   poMinSize,
                                   poMaxSize,
                                   theaderList.size(),
                                   activeSize.get(),
                                   queue.size(),
                                   poIdleTimeMs / 1000));
        }
        
        // 等待下次检查
        Threads.sleepIgnoreException(poIdleTimeMs);
    }
    
    /*********************************************************************************************/
    // 线程池管理
    /*********************************************************************************************/
    
    /**
     * 开启一个新的线程
     */
    private void openThreader() {
        Threader threader = new Threader(this);
        threader.setDaemon(this.isDaemon());
        threader.start();
        synchronized (theaderList) {
            theaderList.add(threader);
        }
    }
    
    /**
     * 关闭所有线程
     */
    private void closeThreaders() {
        synchronized (theaderList) {
            for (Threader threader : theaderList) {
                threader.close();
                threader = null;
            }
            theaderList.clear();
        }
    }
    
    /**
     * 检查线程池
     */
    private void chkThreaders() {
        // 1.找出需要关闭的线程列表
        List<Threader> list = new ArrayList<>();
        synchronized (theaderList) {
            for (Threader value : theaderList) {
                if (theaderList.size() - list.size() <= poMinSize) {break;}
                
                if (value.isIdleTimeout(poIdleTimeMs)) {
                    // 空闲超时的加入到需要关闭列表
                    list.add(value);
                }
            }
        }
        
        // 2.执行关闭操作
        for (Threader threader : list) {
            if (threader.isIdleTimeout(poIdleTimeMs)) {
                // 再作一次空闲超时判断
                synchronized (theaderList) {
                    theaderList.remove(threader);
                }
                
                threader.close();
            }
        }
        
        // 3.清理列表
        list.clear();
        list = null;
    }
    
    /*********************************************************************************************/
    // 线程池处理，处理事件&清理事件&判断事件是否存在
    
    /*********************************************************************************************/
    
    public boolean execute(Runnable command) {
        return execute(command, false);
    }
    
    public synchronized boolean execute(Runnable command, boolean priority) {
        if (!isRunning() || command == null) {return false;}
        
        int threaderSize = theaderList.size();
        int activeSize = getThreaderActiveSize();
        if (activeSize < threaderSize) {
            // 线程池空闲
            queue.post(command, priority);
            return true;
        }
        
        if (queue.size() < threaderSize) {
            // 线程池忙，缓冲一个线程数批次
            queue.post(command, priority);
            return true;
        }
        
        if (threaderSize < poMaxSize) {
            // 线程池较忙，增加线程数至最大
            openThreader();
            queue.post(command, priority);
            return true;
        }
        
        if (queue.size() < poQueueSize) {
            // 线程池繁忙，接近最大处理能力
            queue.post(command, priority);
            return true;
        }
        
        if (isLogger) {
            // 线程池繁忙超限时打印日志
            log.error(String.format("线程池[%s]繁忙超限，事件对队已满，无法接收处理", threadName));
        }
        return false;
    }
    
    /*********************************************************************************************/
    // 线程操作者调用，接受一个事件&完成事件设置数目
    
    /*********************************************************************************************/
    
    Runnable accept() {
        return queue.accept(threadTimeoutMs);
    }
    
    void active() {
        activeSize.getAndIncrement();
    }
    
    void idle() {
        activeSize.getAndDecrement();
    }
    
    /*********************************************************************************************/
    // 线程池中对列信息&操作
    /*********************************************************************************************/
    
    /**
     * 清空队列事件列表
     */
    public void clear() {
        queue.clear();
    }
    
    /**
     * 是否包含某事件
     *
     * @param command 待处理事件
     * @return true|false
     */
    public boolean contains(Runnable command) {
        return queue.contains(command);
    }
    
    public int size() {
        return queue.size();
    }
    
    public boolean isEmpty() {
        return queue.isEmpty();
    }
    
    public Queue<Runnable> getQueue() {
        return queue;
    }
    
    /*********************************************************************************************/
    // 获取线程池运行时参数
    
    /*********************************************************************************************/
    
    public List<Threader> getThreaderList() {
        return Collections.unmodifiableList(theaderList);
    }
    
    public int getThreaderSize() {
        return theaderList.size();
    }
    
    public int getThreaderActiveSize() {
        return activeSize.get();
    }
    
    public int getThreaderIdleSize() {
        return theaderList.size() - activeSize.get();
    }
    
    /*********************************************************************************************/
    // 获取线程池配置参数
    
    /*********************************************************************************************/
    
    public int getPoMinSize() {
        return poMinSize;
    }
    
    public int getPoMaxSize() {
        return poMaxSize;
    }
    
    public int getPoIdleTime() {
        return poIdleTimeMs / 1000;
    }
    
    public int getPoQueueSize() {
        return poQueueSize;
    }


//    public static void main(String[] args) {
////        new ThreaderController().init(1, 2, 4, 30).start();
////        Threads.sleepIgnoreException(1363);
//        HandlerController handlerController = new HandlerController().init(1, 2, 1, 30);
////        handlerController.setDaemon(true);
//        handlerController.start();
//    }
}
